package top.yzlin.dblock.component;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import top.yzlin.dblock.tools.MD5Tools;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class RedisLock implements Lock {
    private String resourceMark;
    private String uniqueId;
    private Jedis jedis;
    private JedisPubSub jedisPubSub;


    public RedisLock(Jedis jedis, String resourceMark) {
        this.resourceMark = resourceMark;
        this.jedis = jedis;
        uniqueId = MD5Tools.getUniqueId();
        jedisPubSub = new JedisPubSub() {
            @Override
            public void onMessage(String channel, String message) {
                this.unsubscribe();
            }
        };
    }

    public String getResourceMark() {
        return resourceMark;
    }

    public String getUniqueId() {
        return uniqueId;
    }

    @Override
    public void lock() {
        if (jedis.setnx("lock." + resourceMark, uniqueId) <= 0) {
            jedis.subscribe(jedisPubSub, "lock." + resourceMark + "." + jedis.get("lock." + resourceMark));
            lock();
        }
    }

    @Override
    public boolean tryLock() {
        return jedis.setnx("lock." + resourceMark, uniqueId) > 0;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        long l = unit.toMillis(time) + System.currentTimeMillis();
        while (System.currentTimeMillis() < l) {
            if (tryLock()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void unlock() {
        if (Objects.equals(jedis.get("lock." + resourceMark), uniqueId)) {
            jedis.del("lock." + resourceMark);
            jedis.publish("lock." + resourceMark + "." + uniqueId, "");
        } else {
            System.out.println("未持有锁");
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        throw new UnsupportedOperationException("不知道这个接口是啥，看都看不懂还实现");
    }

    @Override
    public Condition newCondition() {
        throw new UnsupportedOperationException("Condition也不知道是啥，看都看不懂还实现");
    }
}
